﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using SPMS.Utility;

namespace SPMS.Log
{
    /// <summary>
    /// 日志级别类型转换器
    /// </summary>
    /// <remarks>用于实现其它类型和日志级别类型之间的相互转换</remarks>
    /// <history>
    /// [zanezeng]               2010/1/8 10:07    创建
    /// </history>
    public sealed class LevelTypeConverter : TypeConverter
    {
        #region ---Public Method

        /// <summary>
        /// 返回该转换器是否可以将给定类型的对象转换为此转换器的类型
        /// </summary>
        /// <param name="context"><see cref="T:System.ComponentModel.ITypeDescriptorContext"/>类型描述上下文</param>
        /// <param name="sourceType">类<see cref="T:System.Type"/>的实例，用于描述转化的源类型</param>
        /// <returns>
        /// 如果允许转化则返回<c>true</c>，否则返回<c>false</c>
        /// </returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]   2008-11-14 13:17    Created
        /// </history>
        public override bool CanConvertFrom( ITypeDescriptorContext context, Type sourceType )
        {
            //判断是否为支持的类型
            return IsSupportedType( sourceType ) || base.CanConvertFrom( context, sourceType );
        }

        /// <summary>
        /// 返回该转换器是否可以将日志级别转换为给定的类型
        /// </summary>
        /// <param name="context"><see cref="T:System.ComponentModel.ITypeDescriptorContext"/>类型描述上下文</param>
        /// <param name="destinationType">类<see cref="T:System.Type"/>的实例，用于描述转化的目标类型</param>
        /// <returns>
        /// 如果允许转化则返回<c>true</c>，否则返回<c>false</c>
        /// </returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]   2008-11-14 13:17    Created
        /// </history>
        public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType )
        {
            //判断是否为支持的类型
            return IsSupportedType( destinationType ) || base.CanConvertTo( context, destinationType );
        }

        /// <summary>
        /// 将给定值转换为此转换器的类型
        /// </summary>
        /// <param name="context">类型为<see cref="T:System.ComponentModel.ITypeDescriptorContext"/>的实例</param>
        /// <param name="culture">类型为<see cref="T:System.Globalization.CultureInfo"/>的本地区域性</param>
        /// <param name="value">类型为<see cref="T:System.Object"/>的实例，类型的转化的源对象</param>
        /// <returns>
        /// 类<see cref="T:System.Object"/>的新实例，用于保存类型转化的结果
        /// </returns>
        /// <exception cref="NotSupportedException">无法将指定的对象转化为日志级别对象</exception>
        /// <exception cref="ArgumentNullException"><paramref name="value"/>为<c>null</c>引用。</exception>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]   2008-11-14 13:23    Created
        /// </history>
        public override object ConvertFrom( ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value )
        {
            //断言参数
            ArgumentAssert.AssertArgumentNotNull( value, "value" );

            //获得源类型
            Type sourceType = value.GetType();

            //判断是否为支持的类型
            if (!IsSupportedType( sourceType ))
            {
                //如果为不支持的类型，则调用基类实现
                return base.ConvertFrom( context, culture, value );
            }

            //用于保存模板日志级别
            Level destinationLevel = null;

            //判断源类型是否为字符串
            if (value is string)
            {
                //获得目标日志级别对象
                destinationLevel = LoggingContext.DefaultLevelMap.LookupLevelWithDefault( (string)value, null );

                //判断目标日志级别对象是否为空引用
                if (null == destinationLevel)
                {
                    //生成提示消息
                    string message = string.Format( Properties.Resources.MSG_CONVERTER_NOTSUPPORTED, "LevelTypeConverter", value, typeof( Level ) );

                    //抛出异常
                    throw new NotSupportedException( message );
                }

                //返回模板日志级别
                return destinationLevel;
            }

            //转换为日志级别值
            int levelValue = ObjectUtility.ConvertTo<int>( value );

            //检索日志级别
            destinationLevel = LoggingContext.DefaultLevelMap.LookupLevelWithDefault( levelValue, null );

            //判断目标日志级别对象是否为空引用
            if (null == destinationLevel)
            {
                //返回新创建的日志级别对象
                return new Level( levelValue.ToString(), levelValue );
            }

            //返回目标日志级别
            return destinationLevel;
        }

        /// <summary>
        /// 将给定值转换为此转换器的类型
        /// </summary>
        /// <param name="context">类型为<see cref="T:System.ComponentModel.ITypeDescriptorContext"/>的实例</param>
        /// <param name="culture">类型为<see cref="T:System.Globalization.CultureInfo"/>的本地区域性</param>
        /// <param name="value">类型为<see cref="T:System.Object"/>的实例，类型的转化的源对象</param>
        /// <param name="destinationType">类<see cref="T:System.Type"/>的实例，用于描述转化的目标类型</param>
        /// <returns>
        /// 类<see cref="T:System.Object"/>的新实例，用于保存类型转化的结果
        /// </returns>
        /// <exception cref="NotSupportedException">无法将指定的对象转化为日志级别对象</exception>
        /// <exception cref="ArgumentNullException"><paramref name="destinationType"/>为<c>null</c>引用。</exception>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]   2008-11-14 13:23    Created
        /// </history>
        public override object ConvertTo( ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType )
        {
            //断言参数
            ArgumentAssert.AssertArgumentNotNull( destinationType, "destinationType" );

            //获得源日志级别对象
            Level sourceLevel = value as Level;

            //判断源对象是否为日志级别对象
            if (null != sourceLevel)
            {
                //判断目标类型是否为字符串
                if (destinationType == typeof( string ))
                {
                    //返回日志级别的名称
                    return destinationType.Name;
                }
                //判断是否为支持的类型
                else if (IsSupportedType( destinationType ))
                {
                    //返回转换结果
                    return ObjectUtility.ConvertTo( value, destinationType );
                }
            }

            //调用基类实现
            return base.ConvertTo( context, culture, value, destinationType );
        }

        #endregion

        #region ---Private Method

        /// <summary>
        /// 判断是否能够和给定的类型之间进行相互转换
        /// </summary>
        /// <param name="candidateType">用于判断的类型对象</param>
        /// <returns>
        /// 	<c><c>true</c></c>：能够和给定的类型之间进行相互转换<br/>
        /// 	<c><c>false</c></c>：不能够和给定的类型之间进行相互转换
        /// </returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2010/1/8 10:12    创建
        /// </history>
        private static bool IsSupportedType( Type candidateType )
        {
            //判断目标类型是为空引用
            if (null == candidateType)
            {
                //如果目标类型为空引用，则总是返回不支持
                return false;
            }

            //判断支持的类型中是否包含给定的类型
            return -1 != Array.IndexOf<Type>( SUPPORTED_TARGET_TYPES, candidateType );
        }

        #endregion

        #region ---Field

        /// <summary>
        /// 支持转换的目标类型
        /// </summary>
        private static readonly Type[] SUPPORTED_TARGET_TYPES = new Type[] { typeof( string ), typeof( int ), typeof( short ), typeof( long ), typeof( uint ), typeof( ushort ), typeof( ulong ) };

        #endregion
    }
}
